/**********************************************************************************************************************
 * @file    aadl.h
 * @author  Queclink Hubert.Lee
 * @date    2016-10-22
 * @brief   Application Aided Develop Library, 应用程序辅助开发库头文件
 * @ingroup aadl
 *
 * Copyright (C) 2016 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 *
 * @attention
 * 1. aadl_initialize(): 库初始化函数, 在使用库其它函数前务必调用该函数;
 * 2. !!!如果用户启用了系统日志功能,LOG_ERR及其以上等级的log将自动作为系统日志记录下来!!!
 *
 * @usage
 * 1. aadl_version
 *   当前 AADL 版本号, 字符串.
 * 2. int aadl_initialize(const struct aadl_ops *)
 *   @brief  应用程序辅助开发库初始化函数;
 *   @param  struct aadl_ops *: [I], 系统提供给库的公共函数;
 *   @retval 0:成功, others:错误码
 * 3. int aadl_errno
 *   @brief  记录最后(最近)一次错误码;
 *   @note   当函数返回错误码时可以不记录.
 * 4. const char *errno_str(int errno)
 *   @brief  获取错误码字符串;
 *   @param  errno: [I], 错误码;
 *   @retval 错误码字符串首地址
 * 5. LOG_XXX
 *   @brief  调试信息类型、调试信息等级
 * 6. int aadl_debug_register(char *prefix, char *loglevel)
 *   @brief  注册DEBUG通道;
 *   @param  prefix: [I], 打印信息的前缀, 字符串, 最大32字节, 如"[MODEM]: ";
 *           loglevel: [I], LOG等级, LOG_DEFAULT:"7";
 *   @retval 非负数:DEBUG通道ID, others:错误码
 * 7. int aadl_debug_set(int id, char *loglevel)
 *   @brief  设置DEBUG通道LOG等级;
 *   @param  id: [I], DEBUG通道ID;
 *           loglevel: [I], LOG等级, LOG_DEFAULT:"7", LOG_OFF:关闭通道(不再打印).
 *   @retval 0:成功, others:错误码
 * 8. int aadl_debug_loglevel_get(int id, char *loglevel)
 *   @brief  读取DEBUG通道当前LOG等级;
 *   @param  id: [I], DEBUG通道ID;
 *           loglevel: [O], 读取到的LOG等级, 字符串格式.
 *   @retval 0:成功, others:错误码
 * 9. int aadl_debug(int id, const char *fmt, ...)
 *   @brief  通过DEBUG通道打印信息;
 *   @param  id: [I], DEBUG通道ID;
 *           fmt, ...: [I], <LOG等级>+待打印信息, 有LOG等级则会自动添加前缀信息,
 *             无LOG等级则沿用上一次的等级, 且不会添加前缀信息(直接打印),
 *             CAN NOT BE LOG_OFF;
 *   @note   1)带前缀信息的打印示例: aadl_debug(channel_id, LOG_ERR "Error(%d) occurred.\r\n", error_code);
 *           2)不带前缀信息的打印示例: aadl_debug(channel_id, "%s\r\n", str);
 *           3)本函数最多支持打印 512 个字符, 待打印数据过多请自行分割打印;
 *           4)!!!如果用户启用了系统日志功能,LOG_ERR及其以上等级的log将自动作为系统日志记录下来!!!
 *   @retval 非负数:打印的字符个数, others:错误码
 *
 *********************************************************************************************************************/


#ifndef __AADL_H
#define __AADL_H

/* includes ---------------------------------------------------------------------------------------------------------*/
#include <stddef.h>
#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif


#ifndef _SSIZE_T
#define _SSIZE_T
typedef signed int ssize_t;
#endif /* _SSIZE_T */

/**
 *  The following type defines the control block used to manage
 *  option sets.
 */
typedef unsigned int   aadl_option;

/**
 *  The following constants define the individual options which may
 *  be used to compose an option set.
 */
#define AADL_DEFAULT_OPTIONS   0x00000000

/**
 *  This option constants indicates that the task is to wait on resource.
 */
#define AADL_WAIT           0x00000000
/**
 *  This option constants indicates that the task is to not wait on
 *  the resource.  If it is not available, return immediately with
 *  a status to indicate unsatisfied.
 */
#define AADL_NO_WAIT        0x00000001

/* 紧急:请求优先处理 */
#define AADL_URGENT         0x00000002

/* 保持生效 */
#define AADL_KEEP_ALIVE     0x00000004

/* 保留连带区域(用于Flash存储) */
#define AADL_KEEP_OUTSIDE   0x00000008

/* 1.使用外部缓存区(内部不进行数据缓存);
 * 2.使用内部缓存区(外部不进行数据缓存) */
#define AADL_KEEP_BUFFER    0x00000010

/* 快速(返回), 必须与 AADL_WAIT 搭配使用,
 * 当使用该选项获取某参数值时,可能无法获取到实时值 */
#define AADL_FAST           0x00000020

/* 强制操作 */
#define AADL_FORCE          0x00000040

/* 忽略某些特性,比如忽略命令执行结果 */
#define AADL_IGNORE         0x00000080

/* 保持头部 */
#define AADL_KEEP_HEAD      0x00000100

#define options_is_no_wait(set)     (AADL_NO_WAIT & set)
#define options_is_wait(set)        (!(AADL_NO_WAIT & set))
#define options_is_urgent(set)      (AADL_URGENT & set)
#define options_is_no_urgent(set)   (!(AADL_URGENT & set))
#define options_is_fast(set)        (AADL_FAST & set)

#define AADL_NO_TIMEOUT     0

typedef enum {
    AADL_CMD_SUSPENDED,         /* 挂起(未开始执行) */
    AADL_CMD_IMPLEMENTING,      /* 正在执行 */
    AADL_CMD_COMPLETED,         /* 顺利完成 */
    AADL_CMD_ERR_OCCURRED,      /* 发生错误(无法完成, 包括超时和被动退出) */
    AADL_CMD_ID_INVALID,        /* 无效的命令ID */
}aadl_cmd_state;


#define UNIX_PATH_SEPARATOR     0x2F    /* '/' */
#define WINDOWS_PATH_SEPARATOR  0x5C    /* '\' */

/* abdicate_resource: 仅在操作系统环境有效,在非操作系统环境中务必设置为NULL;
 * system_date_get: 如果无法提供系统日历时间,可以设置为NULL. */
struct aadl_ops {
    int             (*debug)(const char *fmt, ...);         /* 调试接口, 同 printf */
    unsigned int    (*get_ms_since_boot)(void);             /* 获取系统启动时长, 单位ms, 32位可以记录49天 */
    void            (*abdicate_resource)(unsigned int ms);  /* 放弃系统(CPU)资源, 单位ms */
    int             (*system_date_get)(struct tm *);        /* 获取系统日历时间, 仅年月日时分秒有效 */
    char            system_path_separator;                  /* 系统文件路径使用的分隔符,Windows是'\',Unix是'/' */
};

extern const char * const aadl_version;

int aadl_initialize(const struct aadl_ops *);
int aadl_debug_register(char *prefix, char *loglevel);
int aadl_debug_loglevel_get(int id, char *loglevel);
int aadl_debug_set(int id, char *loglevel);
// int aadl_debug(int id, const char *fmt, ...);

extern int aadl_errno;
const char *errno_str(int);


#ifdef __cplusplus
}
#endif

#endif /* __AADL_H */